import java.util.ArrayList;
import java.util.Calendar;

/**
 * A class representing an area a bus can
 * stop in.
 *
 * A location has an ID, an area code and a name
 * @version 1.0
 */
public class Location implements Comparable<Location>
{
    private int locationID;
    private String areaName;
    private String stopName;

    //The edges linked to by this Location
    private ArrayList<Edge> outlist;

    //The minimum distance, set to INFINITY at the start
    private double minDistance;

    //Previous
    private Location previous;
    
    //The previous Service
    private Service previousService;
    
    //Previous edge
    private Edge previousEdge;
    
    //The latest time
    private Calendar latestTime;

    /**
     * Constructs a Location with a given name and area code
     * @param name The name of the bus stop
     * @param areaName The area code of the bus stop
     */
    public Location(String name, String areaName)
    {
        this.stopName = name;
        this.areaName = areaName;

        this.locationID = BusStopInfo.findBusStop(this.areaName, this.stopName);

        this.outlist = new ArrayList<Edge>();
        
        this.minDistance = 32768;
    }

    /**
     * Constructs a Location with just an ID, and then find the
     * area code and stop name.
     * @param locationID The ID of the bus stop or location
     */
    public Location(int locationID)
    {
        if(locationID < 770 || locationID > 817)
        {
            throw new IllegalArgumentException();
        }

        this.locationID = locationID;

        String fullName = BusStopInfo.getFullName(this.locationID);
        String[] names = fullName.split(",\\s*");

        this.areaName = names[1];
        this.stopName = names[0];

        this.outlist = new ArrayList<Edge>();
        
        this.minDistance = 32768;
    }

    /**
     * Constructor which takes all 3 fields of a location.
     * @param locationID The ID of a location
     * @param stopName The name of a location
     * @param areaName The area code of a location
     */
    public Location(int locationID,
                    String stopName,
                    String areaName)
    {
        this.locationID = locationID;
        this.stopName = stopName;
        this.areaName = areaName;

        this.outlist = new ArrayList<Edge>();
        
        this.minDistance = 32768;
    }

    /**
     * Get the location ID of this stop
     * @return The location ID of this stop
     */
    public int getLocationID()
    {
        return this.locationID;
    }

    /**
     *
     * @return The stop name of this stop
     */
    public String getStopName()
    {
        return this.stopName;
    }

    /**
     *
     * @return The Area name of this stop
     */
    public String getAreaName()
    {
        return this.areaName;
    }

    public double getMinDistance()
    {
        return this.minDistance;
    }

    public void setMinDistance(double minDistance)
    {
        this.minDistance = minDistance;
    }

    public ArrayList<Edge> getOutlist()
    {
        return this.outlist;
    }

    public void setPrevious(Location prev)
    {
        this.previous = prev;
    }

    public Location getPrevious()
    {
        return this.previous;
    }

    public void setPreviousEdge(Edge previousEdge) {
        this.previousEdge = previousEdge;
    }

    public Edge getPreviousEdge() {
        return previousEdge;
    }

    public Service getPreviousService() {
        return previousService;
    }

    public void setPreviousService(Service previousService) {
        this.previousService = previousService;
    }

    public Calendar getLatestTime() {
        return latestTime;
    }

    public void setLatestTime(Calendar latestTime) {
        this.latestTime = latestTime;
    }

    public boolean isSameName(String otherName)
    {
        return (this.stopName + ", " + this.areaName).equalsIgnoreCase(otherName);
    }
    
    
    
    

    /**
     * Add a location to this locations outlist
     * @param s The service to add
     * @param target The location to add
     * @param duration The duration of time between this and the target
     */
    public void addEdge(Service s, Location target, int duration)
    {
        Edge e = new Edge(s, s.getStartTime(), duration, target);
        this.outlist.add(e);
    }


    public int compareTo(Location o) {
        return Double.compare(minDistance, o.minDistance);
    }

    @Override
    public boolean equals(Object obj)
    {
        if (obj instanceof Location)
        {
            Location loc = (Location) obj;
            return (this.stopName + this.areaName)
                    .equalsIgnoreCase(loc.stopName + loc.areaName);
        }
        else
            return super.equals(obj);
    }



    @Override
    public String toString()
    {
        String returnString = "";
        for (int i = 0; i < outlist.size(); i++)
            returnString += outlist.get(i).getEndLocation().getStopName() + " ";
        return this.stopName + "\n" + returnString + "\n\n";
    }



    /**
     * Get all the locations nearby this location ID
     * @return an ArrayList representing all nearby locations.
     */
    public ArrayList<Location> getLocationsInArea()
    {
        ArrayList<Location> nearbyLocations = new ArrayList<Location>();
        int locations[] = BusStopInfo.getBusStopsInArea(this.locationID);

        for (int i = 0; i < locations.length; i++)
            nearbyLocations.add(new Location(locations[i]));

        return nearbyLocations;
    }

    public static void main(String[] args)
    {
        database.openBusDatabase();
        int found = TimetableInfo.findRoute("383");
        int[] points = TimetableInfo.getTimingPoints(found);
        for (int i = 0; i < points.length; i++)
            System.out.println("Point " + i + ": " + points[i]);
       // System.out.println("Found ID: " + TimetableInfo.findRoute("383"));
    }


}
